package com.efast.cafe.util;

import java.io.ByteArrayInputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.InputStream;
import java.net.URLEncoder;
import java.util.Date;

import javax.crypto.Mac;
import javax.crypto.spec.SecretKeySpec;

import org.apache.commons.codec.binary.Base64;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.aliyun.oss.ClientConfiguration;
import com.aliyun.oss.ClientException;
import com.aliyun.oss.OSSClient;
import com.aliyun.oss.model.GetObjectRequest;
import com.aliyun.oss.model.OSSObject;
import com.aliyun.oss.model.ObjectMetadata;
import com.aliyun.oss.model.PutObjectResult;
import com.aliyuncs.DefaultAcsClient;
import com.aliyuncs.http.MethodType;
import com.aliyuncs.http.ProtocolType;
import com.aliyuncs.profile.DefaultProfile;
import com.aliyuncs.profile.IClientProfile;
import com.aliyuncs.sts.model.v20150401.AssumeRoleRequest;
import com.aliyuncs.sts.model.v20150401.AssumeRoleResponse;
import com.aliyuncs.sts.model.v20150401.AssumeRoleResponse.Credentials;
import com.efast.cafe.util.date.DateUtils;

/**
 * 阿里云对象存储
 * @author fxm
 *
 */
public class AliyunOSSUtil {
	protected final Logger logger = LoggerFactory.getLogger(getClass());
	private String bucket;
	private OSSClient ossClient; 
	

	// 目前只有"cn-hangzhou"这个region可用, 不要使用填写其他region的值
	public static final String REGION_CN_HANGZHOU = "cn-hangzhou";
	// 当前 STS API 版本
	public static final String STS_API_VERSION = "2015-04-01";

	public static AssumeRoleResponse assumeRole(String accessKeyId, String accessKeySecret, String roleArn,
			String roleSessionName, String policy, ProtocolType protocolType) throws ClientException {
		try {
			// 创建一个 Aliyun Acs Client, 用于发起 OpenAPI 请求
			IClientProfile profile = DefaultProfile.getProfile(REGION_CN_HANGZHOU, accessKeyId, accessKeySecret);
			DefaultAcsClient client = new DefaultAcsClient(profile);

			// 创建一个 AssumeRoleRequest 并设置请求参数
			final AssumeRoleRequest request = new AssumeRoleRequest();
			request.setVersion(STS_API_VERSION);
			request.setMethod(MethodType.POST);
			request.setProtocol(protocolType);
			request.setRoleArn(roleArn);
			request.setRoleSessionName(roleSessionName);
			request.setPolicy(policy);
			//设置临时token有效时间3600s
			request.setDurationSeconds(3600L);
			// 发起请求，并得到response
			final AssumeRoleResponse response = client.getAcsResponse(request);
			return response;
		} catch (Exception e) {
			e.printStackTrace();  
		}
		return null;
	}

	public AliyunOSSUtil(String accesskeyid,String accesskeysecret,String bucket){
		this.bucket = bucket;
		ClientConfiguration conf = new ClientConfiguration();
		conf.setIdleConnectionTime(Integer.parseInt(ConfigUtil.getValue("cafe.oss.idleConnectionTime")));
		String accountendpoint = ConfigUtil.getValue("cafe.oss.accountendpoint");
		ossClient = new OSSClient(accountendpoint, accesskeyid, accesskeysecret,conf);
	}
	
	
	public static AliyunOSSUtil getInstance(String accesskeyid,String accesskeysecret,String bucket){
		return new AliyunOSSUtil(accesskeyid, accesskeysecret,bucket);
	}
	
	public OSSObject getObject(String key){
		return ossClient.getObject(new GetObjectRequest(bucket, key));
	}
	
	public boolean objectIsExists(String key){
		return ossClient.getObject(new GetObjectRequest(bucket, key))!=null?true:false;
	}
	
	public void shutdownClient(){
		if(null!=ossClient){
			ossClient.shutdown();
		}
	}
    
    /** 
     * 删除存储空间buckName 
     * @param ossClient  oss对象 
     * @param bucketName  存储空间 
     */  
    public  void deleteBucket(){    
        ossClient.deleteBucket(bucket);     
        logger.info("删除" + bucket + "Bucket成功");    
    }
    
    /** 
     * 创建模拟文件夹 
     * @param ossClient oss连接 
     * @param bucketName 存储空间 
     * @param folder   模拟文件夹名如"qj_nanjing/" 
     * @return  文件夹名 
     */  
    public String createFolder(String folder){  
        //文件夹名   
        final String keySuffixWithSlash =folder;  
        //判断文件夹是否存在，不存在则创建  
        if(!ossClient.doesObjectExist(bucket, keySuffixWithSlash)){  
            //创建文件夹  
            ossClient.putObject(bucket, keySuffixWithSlash, new ByteArrayInputStream(new byte[0]));  
            logger.info("创建文件夹成功");  
            //得到文件夹名  
            OSSObject object = ossClient.getObject(bucket, keySuffixWithSlash);  
            String fileDir=object.getKey();  
            return fileDir;  
        }  
        return keySuffixWithSlash;  
    }  
    
    /**   
     * 根据key删除OSS服务器上的文件   
     * @param ossClient  oss连接 
     * @param bucketName  存储空间  
     * @param folder  模拟文件夹名 如"qj_nanjing/" 
     * @param key Bucket下的文件的路径名+文件名 如："upload/cake.jpg" 
     */      
    public void deleteFile(String folder, String key){      
         ossClient.deleteObject(bucket, folder + key);     
         logger.info("删除" + bucket + "下的文件" + folder + key + "成功");    
    }
	
	
    /** 
     * 上传图片至OSS 
     * @param ossClient  oss连接 
     * @param file 上传文件（文件全路径如：D:\\image\\cake.jpg） 
     * @param bucketName  存储空间 
     * @param folder 模拟文件夹名 如"qj_nanjing/" 
     * @return String 返回的唯一MD5数字签名 
     * */  
    public   String uploadObject2OSS(File file,String fileSysName, String folder) {  
        String resultStr = null;  
        try {  
            //以输入流的形式上传文件  
            InputStream is = new FileInputStream(file);  
            //文件名  
            String fileName = file.getName();   
            //文件大小  
            Long fileSize = file.length();   
            //创建上传Object的Metadata    
            ObjectMetadata metadata = new ObjectMetadata();  
            //上传的文件的长度  
            metadata.setContentLength(is.available());    
            //指定该Object被下载时的网页的缓存行为  
            metadata.setCacheControl("no-cache");   
            //指定该Object下设置Header  
            metadata.setHeader("Pragma", "no-cache");    
            //指定该Object被下载时的内容编码格式  
            metadata.setContentEncoding("utf-8");    
            //文件的MIME，定义文件的类型及网页编码，决定浏览器将以什么形式、什么编码读取文件。如果用户没有指定则根据Key或文件名的扩展名生成，  
            //如果没有扩展名则填默认值application/octet-stream  
            metadata.setContentType(getContentType(fileName));    
            //指定该Object被下载时的名称（指示MINME用户代理如何显示附加的文件，打开或下载，及文件名称）  
            metadata.setContentDisposition("filename/filesize=" + fileName + "/" + fileSize + "Byte.");  
            //上传文件   (上传文件流的形式)  
            PutObjectResult putResult = ossClient.putObject(bucket, folder + fileSysName, is, metadata);    
            //解析结果  
            resultStr = putResult.getETag();  
        } catch (Exception e) {  
            e.printStackTrace();  
             logger.error("上传阿里云OSS服务器异常." + e.getMessage(), e);    
        }  
        return resultStr;  
    }  
    
    
    
    
    
    /** 
     * 通过文件名判断并获取OSS服务文件上传时文件的contentType 
     * @param fileName 文件名 
     * @return 文件的contentType 
     */  
    public  String getContentType(String fileName){  
        //文件的后缀名  
        String fileExtension = fileName.substring(fileName.lastIndexOf("."));  
        if(".bmp".equalsIgnoreCase(fileExtension)) {  
            return "image/bmp";  
        }  
        if(".gif".equalsIgnoreCase(fileExtension)) {  
            return "image/gif";  
        }  
        if(".jpeg".equalsIgnoreCase(fileExtension) || ".jpg".equalsIgnoreCase(fileExtension)  || ".png".equalsIgnoreCase(fileExtension) ) {  
            return "image/jpeg";  
        }  
        if(".html".equalsIgnoreCase(fileExtension)) {  
            return "text/html";  
        }  
        if(".txt".equalsIgnoreCase(fileExtension)) {  
            return "text/plain";  
        }  
        if(".vsd".equalsIgnoreCase(fileExtension)) {  
            return "application/vnd.visio";  
        }  
        if(".ppt".equalsIgnoreCase(fileExtension) || "pptx".equalsIgnoreCase(fileExtension)) {  
            return "application/vnd.ms-powerpoint";  
        }  
        if(".doc".equalsIgnoreCase(fileExtension) || "docx".equalsIgnoreCase(fileExtension)) {  
            return "application/msword";  
        }  
        if(".xml".equalsIgnoreCase(fileExtension)) {  
            return "text/xml";  
        }  
        //默认返回类型  
        return "image/jpeg";  
    }
	
    /** 
     * 生成图片访问地址
     * @param obj... 第一个参数为有效期
     * 
     * @return 文件的contentType 
     */  
    @SuppressWarnings("deprecation")
		public static String getImgUrl(String url,String imgPath,String accesskeyid,String accesskeysecret,String bucket,String... obj){  
    	String httpUrl="";
    	try{
    		//String url="http://taijinmanager.oss-cn-shanghai.aliyuncs.com/svg.jpg?OSSAccessKeyId=LTAIX64SlXCYq7UD";//taijinmanager
    		String curTime = null;
    		if(obj!=null && obj.length>0){
    			curTime = String.valueOf((new Date()).getTime() / 1000L+new Long(obj[0]));  //有效期xx秒
    		}else{
    			curTime = String.valueOf(DateUtils.addDays(new Date(),2).getTime()/1000L); //默认图片地址2天失效
    		}
    		String VERB="GET"; //表示HTTP 请求的Method，主要有PUT，GET，POST，HEAD，DELETE等
    		String Content_MD5="";//示请求内容数据的MD5值，对消息内容（不包括头部）计算MD5值获得128比特位数字，对该数字进行base64编码而得到。该请求头可用于消息合法性的检查（消息内容是否与发送时一致），如”eB5eJF1ptWaXm4bijSPyxw==”，也可以为空。详情参看RFC2616 Content-MD5
    		String Content_Type="";
    		String EXPIRES =curTime;
    		String CanonicalizedOSSHeaders="";
    		//String CanonicalizedResource ="/taijinmanager/img/20170608/svg.jpg";
    		String CanonicalizedResource ="/"+bucket+"/"+imgPath;
    		//String accesskeysecret = "nXVMi1veDOfWG3DKrYCBLuVCIwuL1Y";//taijinmanager
    		
    		byte[] key = accesskeysecret.getBytes("UTF-8");
    		String encodePolicy =VERB + "\n" 
    				+ Content_MD5 + "\n" 
    				+ Content_Type + "\n" 
    				+ EXPIRES + "\n" 
    				+ CanonicalizedOSSHeaders
    				+ CanonicalizedResource;
    		//System.out.println("encodePolicy = "+encodePolicy);
    		byte[] data = encodePolicy.getBytes("UTF-8");
    		
    		// hmac-sha1
    		Mac mac = Mac.getInstance("HmacSHA1");
    		mac.init(new SecretKeySpec(key, "HmacSHA1"));
    		byte[] sha = mac.doFinal(data);
    		
    		String Signature = URLEncoder.encode(new String(Base64.encodeBase64(sha)));
    		
    		httpUrl = url+"/"+imgPath+"?OSSAccessKeyId="+accesskeyid+"&Expires="+curTime+"&Signature="+Signature;
    	}catch(Exception e){
    		e.printStackTrace();  
            //logger.error("获取阿里云OSS图片访问地址异常." + e.getMessage(), e);    
    	}
		
		return httpUrl;
    }
    
    
    /** 
     * 生成文件下载地址
     * @param obj... 第一个参数为有效期
     * 
     * @return 文件的contentType 
     */  
    @SuppressWarnings("deprecation")
		public static String getDownLoadUrl(String url,String filePath,String accesskeyid,String accesskeysecret,String bucket,String realFileName,String... obj){  
    	String httpUrl="";
    	try{
    		//String url="http://taijinmanager.oss-cn-shanghai.aliyuncs.com/svg.jpg?OSSAccessKeyId=LTAIX64SlXCYq7UD";//taijinmanager
    		String curTime = null;
    		if(obj!=null && obj.length>0){
    			curTime = String.valueOf((new Date()).getTime() / 1000L+new Long(obj[0]));  //有效期xx秒
    		}else{
    			curTime = String.valueOf((new Date()).getTime() / 1000L+7200);//默认两个小时有效
    		}
    		String VERB="GET"; //表示HTTP 请求的Method，主要有PUT，GET，POST，HEAD，DELETE等
    		String Content_MD5="";//示请求内容数据的MD5值，对消息内容（不包括头部）计算MD5值获得128比特位数字，对该数字进行base64编码而得到。该请求头可用于消息合法性的检查（消息内容是否与发送时一致），如”eB5eJF1ptWaXm4bijSPyxw==”，也可以为空。详情参看RFC2616 Content-MD5
    		String Content_Type="";
    		String EXPIRES =curTime;
    		String CanonicalizedOSSHeaders="";
    		//String CanonicalizedResource ="/taijinmanager/img/20170608/svg.jpg";
    		String CanonicalizedResource ="/"+bucket+"/"+filePath+"?response-content-disposition=attachment;filename="+realFileName;
    		//String accesskeysecret = "nXVMi1veDOfWG3DKrYCBLuVCIwuL1Y";//taijinmanager
    		
    		byte[] key = accesskeysecret.getBytes("UTF-8");
    		String encodePolicy =VERB + "\n" 
    				+ Content_MD5 + "\n" 
    				+ Content_Type + "\n" 
    				+ EXPIRES + "\n" 
    				+ CanonicalizedOSSHeaders
    				+ CanonicalizedResource;
    		byte[] data = encodePolicy.getBytes("UTF-8");
    		
    		// hmac-sha1
    		Mac mac = Mac.getInstance("HmacSHA1");
    		mac.init(new SecretKeySpec(key, "HmacSHA1"));
    		byte[] sha = mac.doFinal(data);
    		
    		String Signature = URLEncoder.encode(new String(Base64.encodeBase64(sha)));
    		
    		httpUrl = url+"/"+filePath+"?OSSAccessKeyId="+accesskeyid+"&Expires="+curTime+"&Signature="+Signature+"&response-content-disposition=attachment;filename="+realFileName;
    		
    	}catch(Exception e){
    		e.printStackTrace();  
            //logger.error("获取阿里云OSS图片访问地址异常." + e.getMessage(), e);    
    	}
		
		return httpUrl;
    }
    
    /**
     * 获取临时token
     * @param args
     */
    public static Credentials STSTempToken(){
    	String accessKeyId = ConfigUtil.getValue("cafe.oss.sts.accesskeyid");
		String accessKeySecret =ConfigUtil.getValue("cafe.oss.sts.accesskeysecret");
    	/*String accessKeyId = "LTAIwnlIaaMxQUYg";
		String accessKeySecret = "75c83bWzG2SN1BP9j9obCSrDeFEni5";
		String roleArn = "acs:ram::1364392139355184:role/taijinmanagerfullcontrol";
		String roleSessionName = "alice-001";*/
		// RoleArn 需要在 RAM 控制台上获取
		String roleArn =ConfigUtil.getValue("cafe.oss.sts.rolearn");
		String roleSessionName = ConfigUtil.getValue("cafe.oss.sts.rolesessionname");

		String policy = "{\n" + "    \"Version\": \"1\", \n" + "    \"Statement\": [\n" + "        {\n"
				+ "            \"Action\": [\n" + "                \"oss:ListObjects\",\"oss:GetObject\",\"oss:PutObject\" \n"
				+ "            ], \n" + "            \"Resource\": [\n"
				+ "                \"acs:oss:*:*:taijinmanager\",\"acs:oss:*:*:taijinmanager/*\" \n"
				+ "            ], \n" + "            \"Effect\": \"Allow\"\n" + "        }\n" + "    ]\n" + "}";
		// 此处必须为 HTTPS
		ProtocolType protocolType = ProtocolType.HTTPS;
		
		AssumeRoleResponse assumResponse = assumeRole(accessKeyId, accessKeySecret, roleArn, roleSessionName, policy, protocolType);
		Credentials credentials = assumResponse.getCredentials();
		return credentials;
	
    }
    
	
	public static void main(String[] args) {
//		String accountendpoint = "http://oss-cn-shanghai.aliyuncs.com";
//		String accesskeyid = "LTAIaHzOr6xhs7oT";
//		String accesskeysecret = "RnUshwUi1sAVjnfl0SzmZAdlfr0MS0";
//		String bucket = "taijinapp";
//		AliyunOSSUtil util = AliyunOSSUtil.getInstance(accountendpoint, accesskeyid, accesskeysecret, bucket);
//		File filess=new File("E:\\activex.log");  
//		String md5key = util.uploadObject2OSS(filess, bucket, "imgs/2017-6-12/");
//		System.out.println(md5key);
	}
}
